#pragma once
#include "stdafx.h"
#include "type.h"
#include <list>
#include <map>
#include <vector>


class BSValue
{
public:
	
	
	typedef std::map<std::string, BSValue> ObjectValues;
	typedef std::vector<BSValue>ArrayValues;
	typedef std::vector<std::string> Members;

	static const BSValue null;
	static const int minInt;
	static const int maxInt;
	static const unsigned int maxUInt;


	BSValue( ValueType type = nullValue );
	BSValue( int value );
	BSValue( unsigned int value );
	BSValue( double value );
	BSValue( const char *value );
	BSValue( const char *beginValue, const char *endValue );
	BSValue( const std::string &value );
	BSValue( bool value );
	BSValue( const BSValue &other );
	~BSValue(void);
	BSValue & operator = ( const BSValue &);
    
	void swap( BSValue &other );


	ValueType type() const;

	bool operator <( const BSValue &other ) const;
	bool operator <=( const BSValue &other ) const;
	bool operator >=( const BSValue &other ) const;
	bool operator >( const BSValue &other ) const;

	bool operator ==( const BSValue &other ) const;
	bool operator !=( const BSValue &other ) const;

	
	
	std::string asString() const;

	int asInt() const;
	unsigned int asUInt() const;
	double asDouble() const;
	bool asBool() const;

	bool isNull() const;
	bool isBool() const;
	bool isInt() const;
	bool isUInt() const;
	bool isIntegral() const;
	bool isDouble() const;
	bool isNumeric() const;
	bool isString() const;
	bool isArray() const;
	bool isObject() const;

	bool isConvertibleTo( ValueType other ) const;

	/// Number of values in array or object
	unsigned int size() const;

	/// \brief Return true if empty array, empty object, or null;
	/// otherwise, false.
	bool empty() const;

	/// Return isNull()
	bool operator!() const;

	/// Remove all object members and array elements.
	/// \pre type() is arrayValue, objectValue, or nullValue
	/// \post type() is unchanged
	void clear();

	/// Resize the array to size elements. 
	/// New elements are initialized to null.
	/// May only be called on nullValue or arrayValue.
	/// \pre type() is arrayValue or nullValue
	/// \post type() is arrayValue
	void resize( unsigned int size );

	/// Access an array element (zero based index ).
	/// If the array contains less than index element, then null value are inserted
	/// in the array so that its size is index+1.
	/// (You may need to say 'value[0u]' to get your compiler to distinguish
	///  this from the operator[] which takes a string.)
	BSValue &operator[]( unsigned int index );
	/// Access an array element (zero based index )
	/// (You may need to say 'value[0u]' to get your compiler to distinguish
	///  this from the operator[] which takes a string.)
	const BSValue &operator[]( unsigned int index ) const;
	/// If the array contains at least index+1 elements, returns the element value, 
	/// otherwise returns defaultValue.

	/// Access an object value by name, create a null member if it does not exist.
	BSValue &operator[]( const char *key );
	/// Access an object value by name, returns null if there is no member with that name.
	const BSValue &operator[]( const char *key ) const;
	/// Access an object value by name, create a null member if it does not exist.
	BSValue &operator[]( const std::string &key );
	/// Access an object value by name, returns null if there is no member with that name.
	const BSValue &operator[]( const std::string &key ) const;
	
	/// If the array contains at least index+1 elements, returns the element value, 
	/// otherwise returns defaultValue.
	BSValue get( unsigned int index, const BSValue &defaultValue ) const;
	
	/// Return true if index < size().
	bool isValidIndex( unsigned int index ) const;
	 

	/// Equivalent to jsonvalue[jsonvalue.size()] = value;
	BSValue &append( const BSValue &value );

	/// Return the member named key if it exist, defaultValue otherwise.
	BSValue get( const char *key, const BSValue &defaultValue ) const;

	/// Return the member named key if it exist, defaultValue otherwise.
	BSValue get( const std::string &key,const BSValue &defaultValue ) const;


	/// \brief Remove and return the named member.  
	///
	/// Do nothing if it did not exist.
	/// \return the removed Value, or null.
	/// \pre type() is objectValue or nullValue
	/// \post type() is unchanged
	BSValue removeMember( const char* key );
	/// Same as removeMember(const char*)
	BSValue removeMember( const std::string &key );

	/// Return true if the object has a member named key.
	bool isMember( const char *key ) const;
	/// Return true if the object has a member named key.
	bool isMember( const std::string &key ) const;


	/// \brief Return a list of the member names.
	///
	/// If null, return an empty list.
	/// \pre type() is objectValue or nullValue
	/// \post if type() was nullValue, it remains nullValue
	Members getMemberNames() const;
private:
	BSValue &resolveReference( const char *key );


	union ValueHolder
	{
		int int_;
		unsigned int uint_;
		double real_;
		bool bool_;
		char *string_;
		ArrayValues *array_;
		ObjectValues *map_;
	} value_;

	ValueType type_ : 8;
	int allocated_ : 1;


};

class ValueAllocator
{
public:
	enum { unknown = (unsigned)-1 };

	virtual ~ValueAllocator();

	virtual char *makeMemberName( const char *memberName ) = 0;
	virtual void releaseMemberName( char *memberName ) = 0;
	virtual char *duplicateStringValue( const char *value, 
              unsigned int length = unknown ) = 0;
	virtual void releaseStringValue( char *value ) = 0;
};
